package ao.cps511.a1.base;

import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.glu.GLU;
import java.awt.*;

/**
 *
 */
public abstract class OrthoRenderer
        implements GLEventListener
{
    //--------------------------------------------------------------------
    private final Rectangle WORLD;

    private int viewportWidth;
    private int viewportHeight;


    //--------------------------------------------------------------------
    public OrthoRenderer(int worldWidth, int worldHeight)
    {
        WORLD = new Rectangle(0, 0, worldWidth, worldHeight);
    }


    //--------------------------------------------------------------------
    public void display (GLAutoDrawable drawable)
    {
        GL gl = drawable.getGL();

        gl.glMatrixMode(GL.GL_MODELVIEW);
        gl.glLoadIdentity();
        
        gl.glClear(GL.GL_COLOR_BUFFER_BIT); // | GL.GL_DEPTH_BUFFER_BIT

        display(gl, new GLU());
        gl.glFlush();
    }

    protected abstract void display(GL gl, GLU glu);


    //--------------------------------------------------------------------
    /** Called when the display mode has been changed.
     *      <B>!! CURRENTLY UNIMPLEMENTED IN JOGL !!</B>
     * @param gLDrawable The GLAutoDrawable object.
     * @param modeChanged Indicates if the video mode has changed.
     * @param deviceChanged Indicates if the video device has changed.
     */
    public void displayChanged(
            GLAutoDrawable gLDrawable,
            boolean modeChanged,
            boolean deviceChanged) {}


    //--------------------------------------------------------------------
    /** Called by the drawable immediately after the OpenGL context is
     * initialized for the first time. Can be used to perform one-time OpenGL
     * initialization such as setup of lights and display lists.
     * @param gLDrawable The GLAutoDrawable object.
     */
    public void init(GLAutoDrawable gLDrawable)
    {
        GL gl = gLDrawable.getGL();

        // Enable Smooth Shading
        gl.glShadeModel(GL.GL_SMOOTH);

        // Black Background
        gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
    }


    //--------------------------------------------------------------------
    /** Called by the drawable during the first repaint after the component has
     * been resized. The client can update the viewport and view volume of the
     * window appropriately, for example by a call to
     * GL.glViewport(int, int, int, int); note that for convenience the component
     * has already called GL.glViewport(int, int, int, int)(x, y, width, height)
     * when this method is called, so the client may not have to do anything in
     * this method.
     * @param drawable The GLAutoDrawable object.
     * @param x The X Coordinate of the viewport rectangle.
     * @param y The Y coordinate of the viewport rectanble.
     * @param width The new width of the window.
     * @param height The new height of the window.
     */
    public void reshape(
            GLAutoDrawable drawable,
            int x, int y,
            int width, int height)
    {
        GL gl = drawable.getGL();
        GLU glu = new GLU();

        // save size for viewport reset
        viewportWidth = width;
        viewportHeight = height;

        resetWorldWindow(gl, glu);
    }

    protected void resetWorldWindow (GL gl, GLU glu) {
        // set the world window
        gl.glMatrixMode( GL.GL_PROJECTION );
        gl.glLoadIdentity();
        glu.gluOrtho2D (WORLD.x,
                        WORLD.x + WORLD.width,
                        WORLD.y,
                        WORLD.y + WORLD.height);
        // set viewport
        // args are x, y, width, height
        gl.glViewport( 0, 0, viewportWidth, viewportHeight );
    }
}
